Download picasa web albums photos automatically. This application requires mpod mother board. See also http://mbed.org/users/geodenx/notebook/mpod/
Dependencies: BlinkLed HTTPClient EthernetInterface FatFileSystemCpp MSCFileSystem mbed-rtos mbed
Download picasa web albums photos automatically.
This application requires mpod mother board.
Picasaウェブアルバムから、自動的に写真をダウンロードして、ディジタルフォトフレームに表示します。
動作させるには mpod マザーボード が必要です。
プログラムの中で、ご自分のアルバムのRSSファイルへのURLを指定してからご利用下さい。
main.cpp@2:531722036c0a, 2012-08-24 (annotated)
- Committer:
- togayan
- Date:
- Fri Aug 24 13:07:06 2012 +0000
- Revision:
- 2:531722036c0a
- Parent:
- 0:dfd5cfea7112
- Child:
- 3:ffbb2b22099a
Only when the album is updated, photos are downloaded.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
togayan | 0:dfd5cfea7112 | 1 | #include "mbed.h" |
togayan | 0:dfd5cfea7112 | 2 | #include "MSCFileSystem.h" |
togayan | 0:dfd5cfea7112 | 3 | #include "EthernetInterface.h" |
togayan | 0:dfd5cfea7112 | 4 | #include "HTTPClient.h" |
togayan | 0:dfd5cfea7112 | 5 | #include "HTTPFile.h" |
togayan | 0:dfd5cfea7112 | 6 | #include "BlinkLed.h" |
togayan | 0:dfd5cfea7112 | 7 | #include "tinyxml2.h" |
togayan | 0:dfd5cfea7112 | 8 | |
togayan | 0:dfd5cfea7112 | 9 | using namespace tinyxml2; |
togayan | 0:dfd5cfea7112 | 10 | |
togayan | 0:dfd5cfea7112 | 11 | int GetFile(const char *path, const char *url); |
togayan | 0:dfd5cfea7112 | 12 | int addNewLine(const char* dstPath, const char* srcPath); |
togayan | 0:dfd5cfea7112 | 13 | int summarizeRss(const char* dstPath, const char* srcPath); |
togayan | 2:531722036c0a | 14 | int removePhotos(); |
togayan | 2:531722036c0a | 15 | const char* getExtensionFromUrl(const char* url); |
togayan | 0:dfd5cfea7112 | 16 | |
togayan | 0:dfd5cfea7112 | 17 | EthernetInterface eth; |
togayan | 0:dfd5cfea7112 | 18 | HTTPClient http; |
togayan | 0:dfd5cfea7112 | 19 | MSCFileSystem usb("usb"); |
togayan | 0:dfd5cfea7112 | 20 | BlinkLed led1(LED1, 0.02); |
togayan | 0:dfd5cfea7112 | 21 | BlinkLed led2(LED2, 0.2); |
togayan | 0:dfd5cfea7112 | 22 | BlinkLed ethGreen(p26, 0.02); |
togayan | 0:dfd5cfea7112 | 23 | BlinkLed ethYellow(p25, 0.2); |
togayan | 0:dfd5cfea7112 | 24 | DigitalOut fsusb30s(p9); |
togayan | 0:dfd5cfea7112 | 25 | Timer timer; |
togayan | 0:dfd5cfea7112 | 26 | |
togayan | 0:dfd5cfea7112 | 27 | /***** Please specify "albumRssUrl" *****/ |
togayan | 0:dfd5cfea7112 | 28 | const char* albumRssUrl = "http://picasaweb.google.com/data/feed/base/user/*****/albumid/*****?alt=rss&kind=photo&authkey=*****&hl=ja"; |
togayan | 0:dfd5cfea7112 | 29 | const char* albumRssPath = "/usb/album.xml"; |
togayan | 0:dfd5cfea7112 | 30 | const char* tempPath = "/usb/temp.xml"; |
togayan | 0:dfd5cfea7112 | 31 | const char* summaryPath = "/usb/summary.xml"; |
togayan | 0:dfd5cfea7112 | 32 | |
togayan | 0:dfd5cfea7112 | 33 | int main() |
togayan | 0:dfd5cfea7112 | 34 | { |
togayan | 0:dfd5cfea7112 | 35 | printf("\n\n================================\n"); |
togayan | 0:dfd5cfea7112 | 36 | printf("mpod Picasa Photo frame\n"); |
togayan | 0:dfd5cfea7112 | 37 | printf("================================\n\n"); |
togayan | 0:dfd5cfea7112 | 38 | |
togayan | 0:dfd5cfea7112 | 39 | // FSUSB30 switches to HSD1 (mbed) |
togayan | 0:dfd5cfea7112 | 40 | printf("USB host was switched to HSD1(mbed).\n\n"); |
togayan | 0:dfd5cfea7112 | 41 | fsusb30s = 0; // HSD1 |
togayan | 0:dfd5cfea7112 | 42 | |
togayan | 0:dfd5cfea7112 | 43 | // Network setup |
togayan | 0:dfd5cfea7112 | 44 | printf("Setup EtherNet with DHCP.\n"); |
togayan | 0:dfd5cfea7112 | 45 | eth.init(); //Use DHCP |
togayan | 0:dfd5cfea7112 | 46 | eth.connect(); |
togayan | 0:dfd5cfea7112 | 47 | |
togayan | 0:dfd5cfea7112 | 48 | // Obtain original lastBuildDate |
togayan | 0:dfd5cfea7112 | 49 | char lastBuildDateOriginal[32] = {0}; |
togayan | 0:dfd5cfea7112 | 50 | { |
togayan | 0:dfd5cfea7112 | 51 | XMLDocument docOriginal; |
togayan | 0:dfd5cfea7112 | 52 | if(XML_SUCCESS != docOriginal.LoadFile(summaryPath)) |
togayan | 0:dfd5cfea7112 | 53 | { |
togayan | 0:dfd5cfea7112 | 54 | strcpy(lastBuildDateOriginal, "No original summary.xml in USB memory"); |
togayan | 0:dfd5cfea7112 | 55 | } |
togayan | 0:dfd5cfea7112 | 56 | else |
togayan | 0:dfd5cfea7112 | 57 | { |
togayan | 0:dfd5cfea7112 | 58 | XMLElement* lastBuildDateOriginalElement = docOriginal.FirstChildElement("rss")->FirstChildElement("channel")->FirstChildElement("lastBuildDate"); |
togayan | 0:dfd5cfea7112 | 59 | if(NULL == lastBuildDateOriginalElement) |
togayan | 0:dfd5cfea7112 | 60 | { |
togayan | 0:dfd5cfea7112 | 61 | strcpy(lastBuildDateOriginal, "No \"lastBuildDate\" element in original RSS"); |
togayan | 0:dfd5cfea7112 | 62 | } |
togayan | 0:dfd5cfea7112 | 63 | else |
togayan | 0:dfd5cfea7112 | 64 | { |
togayan | 0:dfd5cfea7112 | 65 | strcpy(lastBuildDateOriginal, lastBuildDateOriginalElement->GetText()); |
togayan | 0:dfd5cfea7112 | 66 | } |
togayan | 0:dfd5cfea7112 | 67 | } |
togayan | 0:dfd5cfea7112 | 68 | } |
togayan | 0:dfd5cfea7112 | 69 | printf("\nlastBuildDate (original): %s\n", lastBuildDateOriginal); |
togayan | 0:dfd5cfea7112 | 70 | |
togayan | 0:dfd5cfea7112 | 71 | // Download Album |
togayan | 0:dfd5cfea7112 | 72 | GetFile(albumRssPath, albumRssUrl); |
togayan | 0:dfd5cfea7112 | 73 | |
togayan | 0:dfd5cfea7112 | 74 | // Summarize RSS |
togayan | 0:dfd5cfea7112 | 75 | addNewLine(tempPath, albumRssPath); |
togayan | 0:dfd5cfea7112 | 76 | summarizeRss(summaryPath, tempPath); |
togayan | 0:dfd5cfea7112 | 77 | |
togayan | 0:dfd5cfea7112 | 78 | // Obtain current lastBuildDate |
togayan | 0:dfd5cfea7112 | 79 | char lastBuildDateCurrent[32] = {0}; |
togayan | 0:dfd5cfea7112 | 80 | |
togayan | 0:dfd5cfea7112 | 81 | XMLDocument docCurrent; |
togayan | 0:dfd5cfea7112 | 82 | if(XML_SUCCESS != docCurrent.LoadFile(summaryPath)) |
togayan | 0:dfd5cfea7112 | 83 | { |
togayan | 0:dfd5cfea7112 | 84 | fsusb30s = 1; // HSD2 |
togayan | 0:dfd5cfea7112 | 85 | error("No current summary.xml in USB memory.\n"); |
togayan | 0:dfd5cfea7112 | 86 | } |
togayan | 0:dfd5cfea7112 | 87 | |
togayan | 0:dfd5cfea7112 | 88 | XMLElement* lastBuildDateCurrentElement = docCurrent.FirstChildElement("rss")->FirstChildElement("channel")->FirstChildElement("lastBuildDate"); |
togayan | 0:dfd5cfea7112 | 89 | if(NULL == lastBuildDateCurrentElement) |
togayan | 0:dfd5cfea7112 | 90 | { |
togayan | 0:dfd5cfea7112 | 91 | fsusb30s = 1; // HSD2 |
togayan | 0:dfd5cfea7112 | 92 | error("No \"lastBuildDate\" element in current RSS.\n"); |
togayan | 0:dfd5cfea7112 | 93 | } |
togayan | 0:dfd5cfea7112 | 94 | strcpy(lastBuildDateCurrent, lastBuildDateCurrentElement->GetText()); |
togayan | 0:dfd5cfea7112 | 95 | printf("\nlastBuildDate (current) : %s\n", lastBuildDateCurrent); |
togayan | 0:dfd5cfea7112 | 96 | |
togayan | 2:531722036c0a | 97 | if( strcmp(lastBuildDateOriginal, lastBuildDateCurrent) != 0 ) |
togayan | 0:dfd5cfea7112 | 98 | { |
togayan | 2:531722036c0a | 99 | printf("lastBuildDate (original) != lastBuildDate (current)\n"); |
togayan | 2:531722036c0a | 100 | if(removePhotos() < 0) |
togayan | 2:531722036c0a | 101 | { |
togayan | 2:531722036c0a | 102 | fsusb30s = 1; // HSD2 |
togayan | 2:531722036c0a | 103 | error("No \"DCIM\" folder in MSD.\n"); |
togayan | 2:531722036c0a | 104 | } |
togayan | 2:531722036c0a | 105 | |
togayan | 2:531722036c0a | 106 | char photoUrl[256] = {0}; |
togayan | 2:531722036c0a | 107 | char photoPath[32] = {0}; |
togayan | 2:531722036c0a | 108 | int photoNo = 1; |
togayan | 2:531722036c0a | 109 | XMLElement* itemElement = docCurrent.FirstChildElement("rss")->FirstChildElement("channel")->FirstChildElement("item"); |
togayan | 2:531722036c0a | 110 | if(NULL == itemElement) |
togayan | 2:531722036c0a | 111 | { |
togayan | 2:531722036c0a | 112 | fsusb30s = 1; // HSD2 |
togayan | 2:531722036c0a | 113 | error("No \"enclosure\" element in current RSS.\n"); |
togayan | 2:531722036c0a | 114 | } |
togayan | 0:dfd5cfea7112 | 115 | strcpy(photoUrl, itemElement->FirstChildElement("enclosure")->Attribute("url")); |
togayan | 2:531722036c0a | 116 | const char* extension = getExtensionFromUrl(photoUrl); |
togayan | 2:531722036c0a | 117 | sprintf(photoPath, "/usb/DCIM/%08d.%s", photoNo, extension); |
togayan | 0:dfd5cfea7112 | 118 | GetFile(photoPath, photoUrl); |
togayan | 0:dfd5cfea7112 | 119 | ++photoNo; |
togayan | 2:531722036c0a | 120 | |
togayan | 2:531722036c0a | 121 | while( (itemElement = itemElement->NextSiblingElement( "item" ) ) != NULL ) |
togayan | 2:531722036c0a | 122 | { |
togayan | 2:531722036c0a | 123 | strcpy(photoUrl, itemElement->FirstChildElement("enclosure")->Attribute("url")); |
togayan | 2:531722036c0a | 124 | sprintf(photoPath, "/usb/DCIM/%08d.jpg", photoNo); |
togayan | 2:531722036c0a | 125 | GetFile(photoPath, photoUrl); |
togayan | 2:531722036c0a | 126 | ++photoNo; |
togayan | 2:531722036c0a | 127 | } |
togayan | 2:531722036c0a | 128 | } |
togayan | 2:531722036c0a | 129 | else |
togayan | 2:531722036c0a | 130 | { |
togayan | 2:531722036c0a | 131 | printf("lastBuildDate (original) == lastBuildDate (current)\n"); |
togayan | 0:dfd5cfea7112 | 132 | } |
togayan | 0:dfd5cfea7112 | 133 | |
togayan | 0:dfd5cfea7112 | 134 | // Wait for the completion of writing to USB Mass Storage Device. |
togayan | 0:dfd5cfea7112 | 135 | wait(1); |
togayan | 0:dfd5cfea7112 | 136 | |
togayan | 0:dfd5cfea7112 | 137 | // FSUSB30 switches to HSD2 (External Device) |
togayan | 0:dfd5cfea7112 | 138 | printf("\nUSB host was switched to HSD2(External Device).\n"); |
togayan | 0:dfd5cfea7112 | 139 | fsusb30s = 1; // HSD2 |
togayan | 0:dfd5cfea7112 | 140 | |
togayan | 0:dfd5cfea7112 | 141 | // blink LED |
togayan | 0:dfd5cfea7112 | 142 | led1.startBlink(); |
togayan | 0:dfd5cfea7112 | 143 | ethGreen.startBlink(); |
togayan | 0:dfd5cfea7112 | 144 | |
togayan | 0:dfd5cfea7112 | 145 | while(true){} |
togayan | 0:dfd5cfea7112 | 146 | } |
togayan | 0:dfd5cfea7112 | 147 | |
togayan | 0:dfd5cfea7112 | 148 | int GetFile(const char *path, const char *url) |
togayan | 0:dfd5cfea7112 | 149 | { |
togayan | 0:dfd5cfea7112 | 150 | led2.startBlink(); |
togayan | 0:dfd5cfea7112 | 151 | ethYellow.startBlink(); |
togayan | 0:dfd5cfea7112 | 152 | printf("\nGetting %s\n", url); |
togayan | 0:dfd5cfea7112 | 153 | |
togayan | 0:dfd5cfea7112 | 154 | timer.stop(); |
togayan | 0:dfd5cfea7112 | 155 | timer.reset(); |
togayan | 0:dfd5cfea7112 | 156 | timer.start(); |
togayan | 0:dfd5cfea7112 | 157 | |
togayan | 0:dfd5cfea7112 | 158 | HTTPFile file(path); |
togayan | 0:dfd5cfea7112 | 159 | HTTPResult retGet = http.get(url, &file); |
togayan | 0:dfd5cfea7112 | 160 | if (retGet != HTTP_OK) |
togayan | 0:dfd5cfea7112 | 161 | { |
togayan | 0:dfd5cfea7112 | 162 | fsusb30s = 1; // HSD2 |
togayan | 0:dfd5cfea7112 | 163 | error("Error in http.get in GetFile(): %d\n", retGet); |
togayan | 0:dfd5cfea7112 | 164 | } |
togayan | 0:dfd5cfea7112 | 165 | file.clear(); |
togayan | 0:dfd5cfea7112 | 166 | |
togayan | 0:dfd5cfea7112 | 167 | timer.stop(); |
togayan | 0:dfd5cfea7112 | 168 | printf("timer.read_ms(): %d\n", timer.read_ms()); |
togayan | 0:dfd5cfea7112 | 169 | |
togayan | 0:dfd5cfea7112 | 170 | led2.finishBlink(); |
togayan | 0:dfd5cfea7112 | 171 | ethYellow.finishBlink(); |
togayan | 0:dfd5cfea7112 | 172 | return (0); |
togayan | 0:dfd5cfea7112 | 173 | } |
togayan | 0:dfd5cfea7112 | 174 | |
togayan | 0:dfd5cfea7112 | 175 | int addNewLine(const char* dstPath, const char* srcPath) |
togayan | 0:dfd5cfea7112 | 176 | { |
togayan | 0:dfd5cfea7112 | 177 | FILE* fpSrc = fopen(srcPath, "r"); |
togayan | 0:dfd5cfea7112 | 178 | if (fpSrc == NULL) |
togayan | 0:dfd5cfea7112 | 179 | { |
togayan | 0:dfd5cfea7112 | 180 | return -1; |
togayan | 0:dfd5cfea7112 | 181 | } |
togayan | 0:dfd5cfea7112 | 182 | |
togayan | 0:dfd5cfea7112 | 183 | FILE* fpDst = fopen(dstPath, "w"); |
togayan | 0:dfd5cfea7112 | 184 | if (fpDst == NULL) |
togayan | 0:dfd5cfea7112 | 185 | { |
togayan | 0:dfd5cfea7112 | 186 | return -1; |
togayan | 0:dfd5cfea7112 | 187 | } |
togayan | 0:dfd5cfea7112 | 188 | |
togayan | 0:dfd5cfea7112 | 189 | int src; |
togayan | 0:dfd5cfea7112 | 190 | int previous = '\0'; |
togayan | 0:dfd5cfea7112 | 191 | while( (src = fgetc(fpSrc)) != EOF ) |
togayan | 0:dfd5cfea7112 | 192 | { |
togayan | 0:dfd5cfea7112 | 193 | if(previous == '>' && src == '<') |
togayan | 0:dfd5cfea7112 | 194 | { |
togayan | 0:dfd5cfea7112 | 195 | fputc('\n', fpDst); |
togayan | 0:dfd5cfea7112 | 196 | } |
togayan | 0:dfd5cfea7112 | 197 | fputc(src, fpDst); |
togayan | 0:dfd5cfea7112 | 198 | previous = src; |
togayan | 0:dfd5cfea7112 | 199 | } |
togayan | 0:dfd5cfea7112 | 200 | |
togayan | 0:dfd5cfea7112 | 201 | fclose(fpDst); |
togayan | 0:dfd5cfea7112 | 202 | fclose(fpSrc); |
togayan | 0:dfd5cfea7112 | 203 | |
togayan | 0:dfd5cfea7112 | 204 | return 0; |
togayan | 0:dfd5cfea7112 | 205 | } |
togayan | 0:dfd5cfea7112 | 206 | |
togayan | 0:dfd5cfea7112 | 207 | int summarizeRss(const char* dstPath, const char* srcPath) |
togayan | 0:dfd5cfea7112 | 208 | { |
togayan | 0:dfd5cfea7112 | 209 | FILE* fpSrc = fopen(srcPath, "r"); |
togayan | 0:dfd5cfea7112 | 210 | if (fpSrc == NULL) |
togayan | 0:dfd5cfea7112 | 211 | { |
togayan | 0:dfd5cfea7112 | 212 | return -1; |
togayan | 0:dfd5cfea7112 | 213 | } |
togayan | 0:dfd5cfea7112 | 214 | |
togayan | 0:dfd5cfea7112 | 215 | FILE* fpDst = fopen(dstPath, "w"); |
togayan | 0:dfd5cfea7112 | 216 | if (fpDst == NULL) |
togayan | 0:dfd5cfea7112 | 217 | { |
togayan | 0:dfd5cfea7112 | 218 | return -1; |
togayan | 0:dfd5cfea7112 | 219 | } |
togayan | 0:dfd5cfea7112 | 220 | |
togayan | 0:dfd5cfea7112 | 221 | char* ptn[] = |
togayan | 0:dfd5cfea7112 | 222 | { |
togayan | 0:dfd5cfea7112 | 223 | "<?xml", |
togayan | 0:dfd5cfea7112 | 224 | "<rss", |
togayan | 0:dfd5cfea7112 | 225 | "<channel", |
togayan | 0:dfd5cfea7112 | 226 | "<lastBuildDate", |
togayan | 0:dfd5cfea7112 | 227 | "<item", |
togayan | 0:dfd5cfea7112 | 228 | "<enclosure", |
togayan | 0:dfd5cfea7112 | 229 | "</item", |
togayan | 0:dfd5cfea7112 | 230 | "</channel", |
togayan | 0:dfd5cfea7112 | 231 | "</rss" |
togayan | 0:dfd5cfea7112 | 232 | }; |
togayan | 0:dfd5cfea7112 | 233 | int ptnSize = sizeof(ptn) / sizeof(char*); |
togayan | 0:dfd5cfea7112 | 234 | |
togayan | 0:dfd5cfea7112 | 235 | char buff[1024] = {0}; |
togayan | 0:dfd5cfea7112 | 236 | while( fgets(buff, 1024, fpSrc) != NULL ) |
togayan | 0:dfd5cfea7112 | 237 | { |
togayan | 0:dfd5cfea7112 | 238 | for(int i = 0; i < ptnSize; ++i) |
togayan | 0:dfd5cfea7112 | 239 | { |
togayan | 0:dfd5cfea7112 | 240 | if( strncmp(buff, ptn[i], strlen(ptn[i])) == 0 ) |
togayan | 0:dfd5cfea7112 | 241 | { |
togayan | 0:dfd5cfea7112 | 242 | fputs(buff, fpDst); |
togayan | 0:dfd5cfea7112 | 243 | break; |
togayan | 0:dfd5cfea7112 | 244 | } |
togayan | 0:dfd5cfea7112 | 245 | } |
togayan | 0:dfd5cfea7112 | 246 | } |
togayan | 0:dfd5cfea7112 | 247 | |
togayan | 0:dfd5cfea7112 | 248 | fclose(fpDst); |
togayan | 0:dfd5cfea7112 | 249 | fclose(fpSrc); |
togayan | 0:dfd5cfea7112 | 250 | |
togayan | 0:dfd5cfea7112 | 251 | return 0; |
togayan | 0:dfd5cfea7112 | 252 | } |
togayan | 2:531722036c0a | 253 | |
togayan | 2:531722036c0a | 254 | int removePhotos() |
togayan | 2:531722036c0a | 255 | { |
togayan | 2:531722036c0a | 256 | if(DirHandle* dir = opendir("/usb/DCIM")) |
togayan | 2:531722036c0a | 257 | { |
togayan | 2:531722036c0a | 258 | int ret = 0; |
togayan | 2:531722036c0a | 259 | while(struct dirent* ent = dir->readdir()) |
togayan | 2:531722036c0a | 260 | { |
togayan | 2:531722036c0a | 261 | char filename[32] = {0}; |
togayan | 2:531722036c0a | 262 | sprintf(filename, "/usb/DCIM/%s", ent->d_name); |
togayan | 2:531722036c0a | 263 | printf("remove %s\n", filename); |
togayan | 2:531722036c0a | 264 | remove(filename); |
togayan | 2:531722036c0a | 265 | ++ret; |
togayan | 2:531722036c0a | 266 | } |
togayan | 2:531722036c0a | 267 | return ret; |
togayan | 2:531722036c0a | 268 | } |
togayan | 2:531722036c0a | 269 | else |
togayan | 2:531722036c0a | 270 | { |
togayan | 2:531722036c0a | 271 | return -1; |
togayan | 2:531722036c0a | 272 | } |
togayan | 2:531722036c0a | 273 | } |
togayan | 2:531722036c0a | 274 | |
togayan | 2:531722036c0a | 275 | const char* getExtensionFromUrl(const char* url) |
togayan | 2:531722036c0a | 276 | { |
togayan | 2:531722036c0a | 277 | const char* tail = url; |
togayan | 2:531722036c0a | 278 | while('\0' != *tail) |
togayan | 2:531722036c0a | 279 | { |
togayan | 2:531722036c0a | 280 | ++tail; |
togayan | 2:531722036c0a | 281 | } |
togayan | 2:531722036c0a | 282 | |
togayan | 2:531722036c0a | 283 | for(const char* p = tail; p >= url; --p) |
togayan | 2:531722036c0a | 284 | { |
togayan | 2:531722036c0a | 285 | if ('/' == *p) |
togayan | 2:531722036c0a | 286 | { |
togayan | 2:531722036c0a | 287 | return tail; |
togayan | 2:531722036c0a | 288 | } |
togayan | 2:531722036c0a | 289 | if ( '.' == *p ) |
togayan | 2:531722036c0a | 290 | { |
togayan | 2:531722036c0a | 291 | return p+1; |
togayan | 2:531722036c0a | 292 | } |
togayan | 2:531722036c0a | 293 | } |
togayan | 2:531722036c0a | 294 | return tail; |
togayan | 2:531722036c0a | 295 | } |