Saturday, July 28, 2018

OpenWRT on Dlink DSL-2730U C1 (no wifi, no DSL)

DSL-2730U was a common DSL modem-router in the heydays of DSL in India, but now that I have moved on to an optical link, I wanted to re-purpose the modem as a router.

Warning: You will no longer have DSL! You might end up with a brick!! There is no wifi yet!!!

The good news is that the modem has a recovery mode which should help recover from most issues. Turn off the modem. Use a pen to hold down the reset button and turn it back on. The power LED should now turn red. You are now in recovery mode.

So these are the steps (roughly) by which I managed to install openwrt on DLink DSL-2730U C1.

1. Figure out the platform and wifi

Version being C1, SoC is BCM6328 and wifi is BCM4313. ROM is 8MB and RAM 32MB. There is no official OpenWRT support for our model. Too bad.

2. Get the ROM

Go to the OpenWRT site, downloads, then look for the generic brcm6328 image. The link below is only a suggestion, perhaps a newer version will work as well.

https://downloads.openwrt.org/releases/17.01.4/targets/brcm63xx/generic/

You need the 8MB generic image, it should be named something like:

96328avng-generic-squashfs-cfe-8M.bin

3. Flash the ROM

Enter recovery mode (hold reset down when you turn it on).

Connect to the computer with an ethernet cable and go to the recovery address at 192.168.1.1.

A simple page loads. Follow instructions to select and flash the previously downloaded rom. This will take a minute. Modem will eventually reboot and you can log into OpenWRT at 192.168.1.1.

4. Set up routing

a. I set up ethernet port 1 as the wan port. Add a new VLAN in Network>Switch. Turn off port 1 in the existing VLAN and set it to 'untagged' in the new one. Set the cpu to tagged in both.

b. Add a new interface in Network>Interfaces. Select the VLAN you just created and select the WAN firewall zone for it. Set up the WAN using the info your ISP gave you, in my case a static ip address.

Now you can connect the device to your regular modem as a router.

Now for the bonus section.

5. Try installing WiFi drivers (but probably a waste of time)

To refresh package list and install the brcmsmac wifi driver:
opkg update
opkg install kmod-brcmsmac
rmmod brcmsmac
modprobe brcmsmac
Now to refresh the configuration files:
rm -f /etc/config/wireless
wifi config
cat /etc/config/wireless
Hopefully you just saw a wireless interface listed. Now you might want to install WPA security:
opkg install wpad-mini
For me the wifi module (BCM4313) is detected and configurable but fails to start up due to some issue with suspend. YMMV.


Friday, September 16, 2016

Script to retrieve and sort Windows 10 Spotlight images

Windows 10 automatically downloads and displays beautiful images on your lock screen, but offers no obvious way to set them as wallpaper. This script tries to help by copying the current set of downloaded images to a folder on your desktop and doing some sorting for you.

You have to create the target folder on your desktop manually first as a sort of sanity check. By default it needs to be named 'spotlight exported'. Then run spotlight.vbs.

spotlight.vbs:

'************************************
'*                                  *
'*  find and copy spotlight images  *
'*                                  *
'************************************
'Important:
'You have to create this folder on your desktop: 
strImageFolderName = "spotlight exported"

'****************************
' Do stuff
'****************************
Const imgError = 0
Const imgLandscape = 1
Const imgPortrait = 2
Const imgSquare = 3
strDebug = ""

Set objShell = CreateObject("WScript.Shell")

strSrcFolder = objShell.ExpandEnvironmentStrings("%localappdata%") & "\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets"
strImgFolder = objShell.SpecialFolders("Desktop") & "\" & strImageFolderName

Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FolderExists(strSrcFolder) Then
    If objFSO.FolderExists(strImgFolder) Then
        msgres = MsgBox ("This script will copy files to '" & strImgFolder & "'." & vbNewLine & "Do you want to continue?", vbYesNo, "Spotlight Image Copy Script")
        if msgres = vbYes then CopyStuff() else Wscript.Echo ("Quitting...")
    Else
        Wscript.Echo "Image folder does not exist " & vbNewLine & strImgFolder
    end if
Else
    Wscript.Echo "Source folder does not exist" & vbNewLine & strSrcFolder
End If

'****************************
' subroutine
' to copy stuff if all is well
'****************************
Sub CopyStuff()
Set objFolder = objFSO.GetFolder(strSrcFolder)
Set colFiles = objFolder.Files
iCopied = 0
iFailed = 0
iSkipped = 0
iTotal = 0
iLandscape = 0
iPortrait = 0
strDebug = ""

CreateFolders
For Each objFile in colFiles
On Error Resume Next
if objFile.size < 100000 then bTooSmall = true else bTooSmall = false
orientation = getOrientation (objFSO.GetAbsolutePathName(objFile))
if orientation = imgPortrait then iPortrait = iPortrait + 1 
if orientation = imgLandscape then iLandscape = iLandscape + 1 
if bTooSmall = false then
if copyFileSorted (objFile, strImgFolder, orientation) <> true then iFailed = iFailed + 1 else iCopied = iCopied + 1
else
iSkipped = iSkipped + 1 
End If
iTotal = iTotal + 1
Next
MsgBox "Copied " & iCopied & " file(s)." & vbNewLine & vbNewLine & "Skipped: " & iSkipped & vbNewLine & "Failed: " & iFailed & _
vbNewLine & vbNewLine & "Portrait: " & iPortrait & ", Landscape: " & iLandscape & _ 
vbNewLine & vbNewLine & "Processed " & iTotal & " file(s) in total.", , "Processing finished"
End Sub

sub CreateFolders()
If not objFSO.FolderExists(strImgFolder & "\Landscape") Then
objFSO.CreateFolder strImgFolder & "\Landscape"
end if
If not objFSO.FolderExists(strImgFolder & "\Portrait") Then
objFSO.CreateFolder strImgFolder & "\Portrait"
end if
end sub

function getOrientation(filepath) 
on error resume next
Err.Clear
Set objImage = CreateObject("WIA.ImageFile")
objImage.LoadFile filepath
If objImage.Width > objImage.Height Then
getOrientation = imgLandscape
elseif objImage.Width < objImage.Height then 
getOrientation = imgPortrait
else
getOrientation = imgSquare
End If
If Err.Number <> 0 Then getOrientation = imgError
Err.Clear
end function

function copyFileSorted(objFile, destFolder, orientation) 
dest2 = destFolder
if orientation = imgLandscape then dest2 = dest2 & "\Landscape"
if orientation = imgPortrait then dest2 = dest2 & "\Portrait"
Err.Clear
objFSO.copyFile objFSO.GetAbsolutePathName(objFile), dest2 & "\" & objFile.Name & ".jpg", false
If Err.Number <> 0 Then
copyFileSorted = false
Err.Clear
else
copyFileSorted = true
End If
strDebug = strDebug & dest2 & " " & orientation & ", "
end function


Sunday, May 8, 2016

Figuring out a proprietary quadrature encoder from an old Logitech mouse

If you wanted a quadrature encoder and can't make sense of the three-pin IR receiver component you found when you ripped up an old Logitech mouse, here's some help.

The receiver chip is likely a custom Logitech chip which uses a single wire interface to communicate with a custom controller. In my case the controller IC is CP5928AM, for either of which a datasheet is nowhere to be found. They be proprietary.

Fortunately, I found a reference to a relevant Logitech patent (US6552716) on Hackaday forums, and while it only explains general operation and doesn't offer exact timings, (and I don't own an oscilloscope), a little trial and error has produced working code.

Based on the patent, I found that data can be read as follows:

  1. You'll need two free I/O pins on your MCU. Connect one each to the IRLED (I'll call it LED) and the data pin of the receiver (I'll call it data pin). Use existing wiring to figure out the pins. Start with LED off, and data pin set to INPUT on the MCU.
  2. Pulse the LED on and then off. This produces a light pulse which changes the state of a couple of SR latches in the receiver to produce an output which you will now read off a parallel-to-serial shifter. 
  3. Change the data pin to OUTPUT and drive the data pin high and then low. Then change it back to INPUT. Now read the data pin. You have your first directional bit.
  4. Again, change the data pin to OUTPUT and drive the data pin high and then low. Then change it back to INPUT. Now read the data pin. You have your second directional bit. 
  5. Each bit indicates rotation in one direction. If both are 0, there is no movement. If both are 1, then you are not reading data fast enough. 
  6. repeat steps 2 to 5. 

Here's the code I wrote to test it with my Arduino:
/*************************************/
/*  Logitech Quadrature Encoder      */
/*  Single wire interface            */
/*  Code based on patent US6552716.  */
/*************************************/

// data, IRLED pins
#define QEDATAPIN 7
#define QELEDPIN 6

int qeOld1, qeOld2, turns=0, overflows=0;

void setup() {
  Serial.begin(115200);
  pinMode(QEDATAPIN, INPUT);
  //turn irled off -- high is OFF
  pinMode(QELEDPIN, OUTPUT);
  digitalWrite(QELEDPIN, HIGH);
  qeOld1=qeOld2=0;
}

//in microseconds, increase if they don't work
#define QE_SENSOR_PULSEWIDTH 2
#define QE_IRLED_PULSEWIDTH 2

inline void qeLEDlightPulse(){
  digitalWrite(QELEDPIN, LOW);
  delayMicroseconds(QE_IRLED_PULSEWIDTH);
  digitalWrite(QELEDPIN, HIGH);
}

inline byte getQEDataBit(){
  //switch to output mode and
  //pulse data line high and then low
  delayMicroseconds(QE_SENSOR_PULSEWIDTH/2);
  pinMode(QEDATAPIN, OUTPUT);
  digitalWrite(QEDATAPIN, HIGH);
  delayMicroseconds(QE_SENSOR_PULSEWIDTH);
  digitalWrite(QEDATAPIN, LOW);
  delayMicroseconds(QE_SENSOR_PULSEWIDTH);
  //switch back to input mode and
  //read data bit
  pinMode(QEDATAPIN, INPUT);
  delayMicroseconds(QE_SENSOR_PULSEWIDTH);
  return digitalRead(QEDATAPIN);
}

void loop() {
  qeLEDlightPulse();
  byte qe1 = getQEDataBit();
  byte qe2 = getQEDataBit();
  
  if(qeOld1!=qe1 || qeOld2!=qe2){
    if(qe1!=0)
      turns++;
    if(qe2!=0)
      turns--;
    if(qe1==qe2 && qe1==1)
      overflows++;
    Serial.print(turns);
    Serial.print("\t-- ");
    Serial.print(overflows);
    Serial.print("\t-- ");
    Serial.print(qe1);
    Serial.println(qe2);
  }
  qeOld1=qe1;
  qeOld2=qe2;
}

India =/= Hindi

 Blogger.com asks:

///"Why not blog in Hindi? With over 500 million speakers around the world, and a rapidly growing online audience, Hindi content could be the next opportunity to get you new readers. You can now use your existing AdSense account to monetize your Hindi content or just create a new one. Get started now."///

No thanks. Because, f*ck you, don't assume that I speak Hindi just because I live somewhere in India.

Friday, July 16, 2010

Fooling Around with an ATMega

In case you find yourself in the exact same circumstances as me--needing use the ATMega16's Timer1 in compare mode, specifically, Clear Timer on Compare (CTC) mode, you might find this quick calculator I hacked together (for Windows) useful. It generates the C code required to set up Timer1, including prescaler settings and 16 bit compare values.

It's VB6, so be warned.

In the unlikely event that you decide to add to this rather than start from scratch, please let me know. :)

Wednesday, October 29, 2008

Getting a "Hello World" X Client to Compile and Run on Ubuntu 8.04 ("Hardy Heron")

Here's how I barely managed it, being a total n00b.

First a little background. Most Linux variants use X Window for GUI, so those who want to try out X for fun (ie, "Aaargghh, it's in the effing syllabus!") can use the nearest Linux box, which might well be Ubuntu these days, as it is for me. The GNU C Compiler is called gcc (of course), and to compile a c file, say hello.c, you can start a Terminal (command prompt) and type:

gcc -o outputfile hello.c

if you type "gcc hello.c", the output goes to "a.out" by default.

So I start with a rather fresh install of Ubuntu 8.04 LTS and the tutorial from (http://tronche.com/gui/x/xlib-tutorial/). I am pleased to find that gcc was installed by default, because the last version I tried didn't have gcc, and I just happened to be stuck without an internet connection then. Great. But this time, when I try to compile anything c or c++, I still end up with errors. Turns out that the one-cd install of Ubuntu installs gcc, but doesn't install the library headers for anything. So unless you have internet access good for a few MBs download, you may be out of luck if you have my set up.

The first step is to install the package "libc6-dev". Go to System > Administration > Synaptic Package Manager. Search and download-install libc6-dev. Now you can compile simple c applications.

For c++, you will need to install the package "g++" (the source file extension .cc is for c++ files--renaming to .c might be useful for the aforementioned tutorial).

You'll also need to find the package for X11 development. Search in Synaptic for "libx11-dev" and install it. (I also added libxcb1-dev, but that is probably unnecessary--I haven't checked :P)

Still the program doesn't compile because, as I find out, you need to reference the X library for the linker:

gcc -lX11 prog2.c

The "-lX11" option links to the X11 library. Finally, the program compiles and shows a window. Whew!

***

Hello World!

What the post title says. I expect to post random, vaguely technological stuff here, so please bear with me.

Here's hoping that someone may find something useful here sometime!

***